home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / v10n19.arc / TALK.ASM < prev    next >
Assembly Source File  |  1991-10-24  |  21KB  |  549 lines

  1.         title   TALK --- Simple terminal emulator
  2.         page    55,132
  3.         .lfcond             ;list false conditionals too
  4.  
  5. ; TALK.ASM  --- Simple terminal emulator program
  6. ; that demonstrates use of the DOS 5 Task Switcher API.
  7. ; Copyright (c) 1991 Ray Duncan
  8. ;
  9. ; Set the equates COM1 and ECHO to TRUE or FALSE as appropriate 
  10. ; for your machine.  This program does not set baud rates or
  11. ; other communications parameters; use the MODE command instead.
  12. ; Exit from TALK.EXE by entering Alt-X.
  13.  
  14. stdout  equ     1                       ; standard output handle
  15.  
  16. cr      equ     0dh                     ; ASCII carriage return
  17. lf      equ     0ah                     ; ASCII line feed
  18.  
  19. AltX    equ     02dh                    ; keycode for Alt-X
  20.  
  21. bufsiz  equ     4096                    ; size of serial port buffer
  22.  
  23. true    equ     -1
  24. false   equ     0
  25.  
  26. com1    equ     false                   ; Use COM1 if nonzero
  27. com2    equ     not com1                ; Use COM2 if nonzero
  28. echo    equ     false                   ; FALSE=full-duplex, 
  29.                                         ; TRUE=half-duplex
  30.  
  31. pic_mask  equ   21h                     ; 8259 int. mask port
  32. pic_eoi   equ   20h                     ; 8259 EOI port
  33.         
  34.         if      com1
  35. com_data equ    03f8h                   ; port assignments for COM1 
  36. com_ier  equ    03f9h
  37. com_mcr  equ    03fch
  38. com_sts  equ    03fdh
  39. com_int  equ    0ch                     ; COM1 interrupt number
  40. int_mask equ    10h                     ; IRQ4 mask for 8259
  41.         endif
  42.  
  43.         if      com2
  44. com_data equ    02f8h                   ; port assignments for COM2
  45. com_ier  equ    02f9h
  46. com_mcr  equ    02fch
  47. com_sts  equ    02fdh
  48. com_int  equ    0bh                     ; COM2 interrupt number 
  49. int_mask equ    08h                     ; IRQ3 mask for 8259
  50.         endif
  51.  
  52. _DATA   segment word public 'DATA'
  53.  
  54. in_char db      0                       ; PC keyboard input char.
  55. in_flag db      0                       ; <>0 if char waiting
  56.  
  57. msg1    db      cr,lf,'Terminal emulator running...',cr,lf
  58. msg1_len equ $-msg1
  59.  
  60. msg2    db      cr,lf,'Exit from terminal emulator.',cr,lf
  61. msg2_len equ $-msg2
  62.  
  63. oldcomm dd      0                       ; original contents of serial 
  64.                                         ; port interrupt vector
  65.  
  66. switcher dd     0                       ; address of task switcher's
  67.                                         ; service entry point
  68.  
  69. swvers  dd      0                       ; pointer to SWVERSION structure
  70.                                         ; returned by task switcher
  71.  
  72. cbinfo  label   word                    ; switcher callback info structure
  73. cbnext  dd      0                       ; addr of next structure in chain
  74. cbentry dd      callback                ; entry point for notify function
  75.         dd      0                       ; reserved
  76. cbapi   dd      apiinfo                 ; addr of list of api info strucs
  77.  
  78. apiinfo dw      0                       ; empty list of api info structures
  79.  
  80. hooked  dw      0                       ; nonzero if we are hooked into
  81.                                         ; switcher notification chain
  82.  
  83. asc_in  dw      0                       ; input pointer to ring buffer
  84. asc_out dw      0                       ; output pointer to ring buffer
  85.  
  86. asc_buf db      bufsiz dup (?)          ; communications buffer
  87.  
  88. _DATA   ends
  89.  
  90. _TEXT   segment word public 'CODE'
  91.  
  92.         assume  cs:_TEXT,ds:_DATA,ss:_STK
  93.  
  94. talk    proc    far                     
  95.  
  96.         mov     ax,_DATA                ; make our data addressable 
  97.         mov     ds,ax
  98.         mov     es,ax
  99.  
  100.         call    hook                    ; try and hook switcher
  101.         jc      talk1                   ; jump, function failed
  102.         mov     hooked,-1               ; set flag that we are chained
  103.  
  104. talk1:  call    asc_enb                 ; enable communications port
  105.         mov     dx,offset msg1          ; display message
  106.         mov     cx,msg1_len             ; 'Terminal emulator running'
  107.         mov     bx,stdout               ; BX = standard output handle
  108.         mov     ah,40h                  ; Fxn 40H = write file or device
  109.         int     21h                     ; transfer to MS-DOS
  110.  
  111. talk2:  call    pc_stat                 ; keyboard character waiting?
  112.         jz      talk4                   ; nothing waiting, jump
  113.         call    pc_in                   ; read keyboard character
  114.         cmp     al,0                    ; is it a function key?
  115.         jne     talk3                   ; not function key, jump
  116.         call    pc_in                   ; function key, get 2nd part
  117.         cmp     al,AltX                 ; was it Alt-X?
  118.         je      talk5                   ; yes, terminate program
  119.         push    ax                      ; no, send to comm port
  120.         xor     al,al                   ; send lead byte (0)
  121.         call    com_out
  122.         pop     ax                      ; send function key code
  123.         call    com_out
  124.         jmp     talk2                   ; get another key
  125.  
  126. talk3:  if      echo                    ; keyboard character received
  127.         push    ax                      ; if half-duplex, echo
  128.         call    pc_out                  ; character to PC display
  129.         pop     ax              
  130.         endif
  131.         call    com_out                 ; send char to serial port
  132.  
  133. talk4:  call    com_stat                ; serial port input waiting?
  134.         jz      talk2                   ; nothing waiting, jump
  135.         call    com_in                  ; read char from serial port 
  136.         call    pc_out                  ; send it to PC display
  137.         jmp     talk4                   ; see if any more waiting
  138.  
  139. talk5:  call    asc_dsb                 ; release comm hardware
  140.         cmp     hooked,0                ; did we hook task switcher?
  141.         je      talk6                   ; no, jump
  142.         call    unhook                  ; release switcher hooks
  143.  
  144. talk6:  mov     dx,offset msg2          ; display farewell message
  145.         mov     cx,msg2_len             ; DX=addr, CX=length
  146.         mov     bx,stdout               ; BX = standard output handle 
  147.         mov     ah,40h                  ; Fxn 40H = write device
  148.         int     21h                     ; transfer to MS-DOS    
  149.  
  150.         mov     ax,4c00h                ; terminate program with
  151.         int     21h                     ; return code = 0
  152.  
  153. talk    endp
  154.  
  155. ; The variable OLDMUX holds the previous contents of the Int 2FH 
  156. ; vector.  The variable is in the code segment so that it is 
  157. ; addressable at interrupt time without changing DS.
  158. oldmux  dd      0                       ; prev owner of Int 2FH
  159.  
  160. ;
  161. ; HOOK - Hook switcher notification chain and multiplex interrupt.
  162. ;
  163. ; Call with:    Nothing
  164. ; Returns:      Carry = clear if switcher was hooked
  165. ;               Carry = set if switcher not present or could
  166. ;                       not be hooked.
  167. ; Destroys:     AX, BX, CX, DX, DI, ES
  168. ;
  169. hook    proc    near                    
  170.  
  171.         xor     bx,bx                   ; check if switcher present
  172.         mov     di,bx                   ; BX, ES:DI must be zero
  173.         mov     es,bx
  174.         mov     ax,4b02h                ; multiplex function 4b02h
  175.         int     2fh                     ; is detect switcher call
  176.  
  177.         mov     ax,es                   ; check for ES:DI=0 
  178.         or      ax,di
  179.         jz      hook2                   ; jump if no switcher
  180.  
  181.         mov     word ptr switcher,di    ; save address of switcher 
  182.         mov     word ptr switcher+2,es  ; service entry point
  183.         xor     ax,ax                   ; get pointer to switcher's
  184.         call    [switcher]              ; version data structure
  185.         jc      hook2                   ; jump, function failed
  186.  
  187.         mov     word ptr swvers,bx      ; otherwise pointer was
  188.         mov     word ptr swvers+2,es    ; returned in ES:BX
  189.         cmp     word ptr es:[bx],1      ; check switcher protocol version
  190.         jne     hook2                   ; we insist on version 1.0 or we
  191.         cmp     word ptr es:[bx+2],0    ; don't hook notification chain
  192.         jne     hook2                   ; jump, not 1.0
  193.  
  194.         mov     ax,4                    ; now hook notification chain
  195.         mov     di,ds                   ; switcher function = 4
  196.         mov     es,di                   ; ES:DI = addr of switcher
  197.         mov     di,offset _DATA:cbinfo  ; callback info structure
  198.         call    [switcher]              ; call switcher entry point
  199.         jc      hook2                   ; jump, function failed
  200.  
  201.         mov     ax,352fh                ; get current vector for
  202.         int     21h                     ; multiplex interrupt 2FH
  203.         mov     word ptr oldmux+2,es    ; and save it
  204.         mov     word ptr oldmux,bx
  205.  
  206.         push    ds                      ; save our data segment
  207.         mov     ax,cs                   ; set DS:DX = address
  208.         mov     ds,ax                   ; of our multiplex handler
  209.         mov     dx,offset muxisr        ; to hook Int 2FH
  210.         mov     ax,252fh                ; Fxn 25H = set vector
  211.         int     21h                     ; transfer to MS-DOS
  212.         pop     ds                      ; restore data segment
  213.         clc                             ; return carry = clear
  214.         ret                             ; if switcher was hooked        
  215.  
  216. hook2:  stc                             ; return carry = set
  217.         ret                             ; if switcher not hooked
  218.  
  219. hook    endp
  220.  
  221. ;
  222. ; UNHOOK - Release switcher notification chain and multiplex interrupt.
  223. ;
  224. ; Call with:    Nothing
  225. ; Returns:      Nothing
  226. ; Destroys:     AX, DX, DI, ES
  227. ;
  228. unhook  proc    near                    
  229.  
  230.         push    ds                      ; save our data segment
  231.         lds     dx,oldmux               ; load address of previous
  232.                                         ; multiplex interrupt owner
  233.         mov     ax,252fh                ; Fxn 25H = set vector
  234.         int     21h                     ; transfer to MS-DOS    
  235.         pop     ds                      ; restore data segment
  236.  
  237.         mov     ax,5                    ; unhook from notify chain
  238.         mov     di,ds                   ; switcher function = 5
  239.         mov     es,di                   ; ES:DI = address of
  240.         mov     di,offset _DATA:cbinfo  ; callback info structure
  241.         call    [switcher]              ; call switcher entry point     
  242.         ret
  243. unhook  endp
  244.  
  245. ;
  246. ; MUXISR - Handler for multiplex interrupt.
  247. ;
  248. ; Call with:    AH = multiplex number, other registers vary.
  249. ; Returns:      ES:BX = address of callback info structure
  250. ;               if multiplex function 4BH subfunction 01H detected,
  251. ;               otherwise changes nothing, chains to previous owner.
  252. ; Destroys:     Nothing
  253. ;
  254. muxisr  proc    far
  255.  
  256.         cmp     ax,4b01h                ; is this Build Notify Chain?
  257.         je      mux2                    ; yes, process it
  258.         jmp     [oldmux]                ; no, chain to old handler
  259.  
  260. mux2:   push    ds                      ; save updated switcher
  261.         push    ax                      ; entry point address
  262.         mov     ax,_DATA
  263.         mov     ds,ax
  264.         mov     word ptr switcher+2,cx
  265.         mov     word ptr switcher,dx
  266.         pop     ax
  267.         pop     ds
  268.         pushf                           ; call down through the
  269.         call    [oldmux]                ; multiplex handler chain
  270.         push    ds                      ; now save address of next
  271.         push    ax                      ; guy's callback info structure
  272.         mov     ax,_DATA                ; in our callback info structure
  273.         mov     ds,ax
  274.         mov     word ptr cbnext,bx
  275.         mov     word ptr cbnext+2,es
  276.         mov     es,ax                   ; let ES:BX = address of
  277.         mov     bx,offset _DATA:cbinfo  ; our callback info structure
  278.         pop     ax                      ; and pass it back to switcher
  279.         pop     ds
  280.         iret                            ; return from multiplex interrupt
  281.  
  282. muxisr  endp
  283.  
  284. ;
  285. ; CALLBACK - Switcher callback function installed by HOOK and MUXISR.
  286. ;            Looks for session switch notifications and refuses same.
  287. ;
  288. ; Call with:    AX = notification type, other registers vary.
  289. ; Returns:      AX <> 0 if Query Suspend Session or Suspend Session
  290. ;               notifications, otherwise AX = 0.
  291. ; Destroys:     Nothing
  292. ;
  293. callback proc   far                     
  294.  
  295.         cmp     ax,1                    ; is it Query Suspend callback?
  296.         je      callb2                  ; yes, return 1 to block suspend
  297.         cmp     ax,2                    ; is it Suspend Session callback?
  298.         je      callb2                  ; yes, return 1 to block suspend
  299.         xor     ax,ax                   ; else return success
  300.  
  301. callb2: retf
  302.  
  303. callback endp
  304.  
  305. ;
  306. ; COM_STAT - Check communications port status
  307. ;
  308. ; Call with:    Nothing
  309. ; Returns:      Zero flag = false if character ready
  310. ;               Zero flag = true if no character waiting
  311. ; Destroys:     Nothing
  312. ;
  313. com_stat proc   near   
  314.  
  315.         push    ax                      ; save AX
  316.         mov     ax,asc_in               ; compare ring buffer pointers
  317.         cmp     ax,asc_out              ; to set Zero flag
  318.         pop     ax                      ; restore AX
  319.         ret                             ; return to caller      
  320.  
  321. com_stat endp
  322.  
  323. ;
  324. ; COM_IN - Get character from serial port
  325. ;
  326. ; Call with:    Nothing
  327. ; Returns:      AL = character
  328. ; Destroys:     Nothing
  329. ;
  330. com_in  proc    near                    
  331.  
  332.         push    bx                      ; save register BX
  333.  
  334. com_in1:                                ; if no char waiting, wait
  335.         mov     bx,asc_out              ; until one is received
  336.         cmp     bx,asc_in
  337.         je      com_in1                 ; jump, nothing waiting
  338.         mov     al,[bx+asc_buf]         ; extract char from buffer
  339.         inc     bx                      ; update buffer pointer 
  340.         cmp     bx,bufsiz               ; time to wrap pointer?
  341.         jne     com_in2                 ; no, jump
  342.         xor     bx,bx                   ; yes, reset pointer 
  343. com_in2:                        
  344.         mov     asc_out,bx              ; store updated pointer
  345.         pop     bx                      ; restore register BX
  346.         ret                             ; and return to caller
  347.  
  348. com_in  endp
  349.  
  350. ;
  351. ; COM_OUT - Transmit character to serial port
  352. ;
  353. ; Call with:    AL = character
  354. ; Returns:      Nothing
  355. ; Destroys:     Nothing
  356. ;
  357. com_out proc    near   
  358.  
  359.         push    dx                      ; save register DX
  360.         push    ax                      ; save character to send
  361.         mov     dx,com_sts              ; DX = status port address
  362.  
  363. com_out1:                               ; check if transmit buffer
  364.         in      al,dx                   ; is empty (TBE bit = set)
  365.         and     al,20h
  366.         jz      com_out1                ; no, must wait
  367.         pop     ax                      ; retrieve character 
  368.         mov     dx,com_data             ; DX = data port address
  369.         out     dx,al                   ; transmit the character
  370.         pop     dx                      ; restore register DX
  371.         ret                             ; and return to caller
  372.  
  373. com_out endp
  374.  
  375. ;
  376. ; PC_STAT - Get keyboard status
  377. ;
  378. ; Call with:    Nothing
  379. ; Returns:      Zero flag = false if character ready
  380. ;               Zero flag = true if no character waiting
  381. ; Destroys:     DX
  382. ;
  383. pc_stat proc    near                    
  384.  
  385.         mov     al,in_flag              ; if character already    
  386.         or      al,al                   ; waiting, return status   
  387.         jnz     pc_stat1                ; in Zero flag
  388.         mov     ah,6                    ; otherwise call DOS to
  389.         mov     dl,0ffh                 ; determine keyboard status
  390.         int     21h
  391.         jz      pc_stat1                ; jump if no key ready
  392.         mov     in_char,al              ; got key, save it for
  393.         mov     in_flag,0ffh            ; "pc_in" routine
  394.  
  395. pc_stat1:                               ; return to caller with
  396.         ret                             ; status in Zero flag
  397.  
  398. pc_stat endp
  399.  
  400. ;
  401. ; PC_IN - Get character from keyboard
  402. ;
  403. ; Call with:    Nothing
  404. ; Returns:      AL = character
  405. ; Destroys:     DX
  406. ;
  407. pc_in   proc    near
  408.  
  409.         mov     al,in_flag              ; key already waiting?  
  410.         or      al,al
  411.         jnz     pc_in1                  ; yes,return it to caller
  412.         call    pc_stat                 ; no, try and read char.
  413.         jmp     pc_in
  414. pc_in1: mov     in_flag,0               ; clear char. waiting flag
  415.         mov     al,in_char              ; and return AL = char.
  416.         ret 
  417.  
  418. pc_in   endp
  419.  
  420. ;
  421. ; PC_OUT - Send character to PC screen
  422. ;
  423. ; Call with:    AL = character
  424. ; Returns:      Nothing
  425. ; Destroys:     AX, DX
  426. ;
  427. pc_out  proc    near                    
  428.  
  429.         mov     dl,al                   ; DL = char to output
  430.         mov     ah,6                    ; function 6 = direct I/O
  431.         int     21h                     ; transfer to MS-DOS
  432.         ret                             ; return to caller
  433.  
  434. pc_out  endp
  435.  
  436. ;
  437. ; ASC_ENB - Enable comm port, capture communications interrupt
  438. ;
  439. ; Call with:    Nothing
  440. ; Returns:      Nothing
  441. ; Destroys:     AX, BX, DX, ES
  442. ;
  443. asc_enb proc    near          
  444.  
  445.         mov     ax,3500h+com_int        ; save address of previous
  446.         int     21h                     ; owner of comm interrupt
  447.         mov     word ptr oldcomm+2,es   ; function 35H returns
  448.         mov     word ptr oldcomm,bx     ; vector in ES:BX
  449.  
  450.                                         ; install our comm handler
  451.         push    ds                      ; save our data segment
  452.         mov     ax,cs                   ; DS:DX = address of
  453.         mov     ds,ax                   ; comm interrupt handler
  454.         mov     dx,offset asc_isr
  455.         mov     ax,2500h+com_int        ; Fxn 25H = set vector
  456.         int     21h                     ; transfer to MS-DOS
  457.         pop     ds                      ; restore data segment
  458.         
  459.         mov     dx,com_mcr              ; set modem control reg.
  460.         mov     al,0bh                  ; DTR and OUT2 bits
  461.         out     dx,al                   ; to enable interrupts
  462.  
  463.         mov     dx,com_ier              ; set interrupt enable 
  464.         mov     al,1                    ; register on serial
  465.         out     dx,al                   ; port controller
  466.  
  467.         in      al,pic_mask             ; read 8259 interrupt mask
  468.         and     al,not int_mask         ; set mask for COM port
  469.         out     pic_mask,al             ; write new 8259 mask
  470.  
  471.         ret                             ; back to caller
  472.  
  473. asc_enb endp
  474.  
  475. ;
  476. ; ASC_DSB - Release communications interrupt, disable comm hardware
  477. ;
  478. ; Call with:    Nothing
  479. ; Returns:      Nothing
  480. ; Destroys:     AX, DX
  481. ;
  482. asc_dsb proc    near  
  483.         
  484.         in      al,pic_mask             ; read 8259 interrupt mask
  485.         or      al,int_mask             ; reset mask for COM port
  486.         out     pic_mask,al             ; write new 8259 mask
  487.  
  488.         push    ds                      ; save our data segment
  489.         lds     dx,oldcomm              ; DX:DX = address of prev
  490.                                         ; comm interrupt handler    
  491.         mov     ax,2500h+com_int        ; Fxn 25H = set vector
  492.         int     21h                     ; transfer to MS-DOS    
  493.         pop     ds                      ; restore data segment
  494.  
  495.         ret                             ; back to caller
  496.  
  497. asc_dsb endp
  498.  
  499. ;
  500. ; ASC_ISR - Communications interrupt service routine
  501. ; Call with:    Nothing
  502. ; Returns:      Nothing
  503. ; Destroys:     Nothing
  504. ;
  505. asc_isr proc    far    
  506.  
  507.         sti                             ; turn interrupts back on
  508.         push    ax                      ; save registers
  509.         push    bx
  510.         push    dx
  511.         push    ds
  512.  
  513.         mov     ax,_DATA                ; make our data segment 
  514.         mov     ds,ax                   ; addressable
  515.  
  516.         mov     dx,com_data             ; DX = data port address
  517.         in      al,dx                   ; read this character
  518.         mov     bx,asc_in               ; get buffer pointer
  519.         mov     [asc_buf+bx],al         ; store this character
  520.         inc     bx                      ; bump pointer
  521.         cmp     bx,bufsiz               ; time for wrap?
  522.         jne     asc_isr1                ; no, jump
  523.         xor     bx,bx                   ; yes, reset pointer
  524.  
  525. asc_isr1:                               ; store updated pointer
  526.         mov     asc_in,bx
  527.  
  528.         mov     al,20h                  ; send EOI to 8259
  529.         out     pic_eoi,al
  530.  
  531.         pop     ds                      ; restore all registers
  532.         pop     dx
  533.         pop     bx
  534.         pop     ax
  535.         iret                            ; return from interrupt
  536.  
  537. asc_isr endp
  538.  
  539. _TEXT   ends
  540.  
  541. _STK    segment para stack 'STACK'
  542.  
  543.         db      128 dup (?)
  544.  
  545. _STK    ends
  546.  
  547.         end     talk            
  548.  
  549.